package com.zk.config.web.controller;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.NoAuthException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.google.gson.Gson;
import com.zk.config.api.test.Test;
import com.zk.config.web.constants.Constants;
import com.zk.config.web.model.TreeData;
import com.zk.config.web.model.ZkData;
import com.zk.config.web.op.Zk;

import lombok.Setter;

@Controller
@RequestMapping("/read")
public class ZkReadController {
	private static final Logger log = LoggerFactory.getLogger(ZkReadController.class);
	@Setter
	@Value("${zookeeper.backup.directory}")
	private String backupDirPath;
	
//	@Value("${user}")
//	private String user;
//	@Value("${userName}")
//	private String userName;
//	@Resource
//	private Properties configProperties;
//	@Resource
//	private Test test;
	
	private Gson gson = new Gson();
	@RequestMapping("/addr")
	public String addr(HttpServletRequest request, RedirectAttributes attr, Model model, @RequestParam(required = true) String cxnstr, @RequestParam(required = false) String path) {
		if (StringUtils.isBlank(cxnstr)) {
			return "redirect:/";
		}
//		// 这里是测试注入的代码
//		System.out.println("############################user="+ user + ",userName=" + userName);
//		// 这里是测试注入的动态变化的值的代码
//		System.out.println("#######configProperties######user="+configProperties.getProperty("user") + ",userName=" + configProperties.getProperty("userName"));
//		test.init();
		
		HttpSession session = request.getSession();
		session.setAttribute(Constants.CX_STR, cxnstr);
		attr.addFlashAttribute(Constants.CX_STR, StringUtils.trimToEmpty(cxnstr));
		model.addAttribute("zkpath", StringUtils.trimToEmpty(path));
		BaseMsg baseMsg = (BaseMsg)session.getAttribute("baseMsg");
		if (baseMsg == null) {
			baseMsg = new BaseMsg();
		} else {
			session.removeAttribute("baseMsg");
		}
		File fileDir = new File(backupDirPath);
		List<String> fileList = new ArrayList<>();
		if (fileDir != null && fileDir.exists()) {
			File[] files = fileDir.listFiles();
			if (files != null && files.length > 0) {
				for(File file:files) {
					fileList.add(file.getName());
				}
				fileList.sort((a,b) -> {
					if (a == null || b == null) return -1;
					String[] as = a.split("_");
					String[] bs = b.split("_");
					if (as.length != 2 || bs.length != 2) return -1;
					return bs[1].compareTo(as[1]);
					});
			}
		} else {
			if (!fileDir.mkdirs()) {
				baseMsg.addErrMsg("备份目录不存在，创建失败，请检查备份目录是否正确！");
			}
		}
		model.addAttribute("fileList", fileList);
		model.addAttribute("baseMsg", baseMsg);
		return "node";
	}
	
	@RequestMapping("/node")
	public void node(HttpServletRequest request, HttpServletResponse response) {
		HttpSession session = request.getSession();
		String cxnstr = (String) session.getAttribute(Constants.CX_STR);
		String path = request.getParameter("path");
		response.setContentType("application/json;charset=UTF-8");
		if (StringUtils.isBlank(cxnstr)) {
			try {
				response.getWriter().print("");
			} catch (IOException e) {
				e.printStackTrace();
			}
			return;
		}
		Zk reader = new Zk(cxnstr);
		List<TreeData> tdList = new ArrayList<>();
		TreeData td = new TreeData();
		td.setText("/");
		Map<String, String> state = new HashMap<>();
		state.put("opened", "true");
		td.setState(state);
		List<TreeData> ctdList = new ArrayList<>();
		td.setChildren(ctdList);
		tdList.add(td);
		getChildren(reader, "/", ctdList, path);
		try {
			response.getWriter().print(gson.toJson(tdList));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void getChildren(Zk reader, String path, List<TreeData> tdList, String checkPath){
		try {
			List<String> children = reader.getChildren(path);
			if (CollectionUtils.isNotEmpty(children)) {
				Collections.sort(children);
			} else {
				return;
			}
			
			for(String c:children) {
				TreeData td = new TreeData();
				td.setText(c);
				String cpath = path != null && !"/".equals(path)?(reader.getPath(path)+"/"+c):c;
				List<TreeData> ctdList = new ArrayList<>();
				getChildren(reader, cpath, ctdList, checkPath);
				if(ctdList.size() == 0) {
					td.setIcon("file");
					if(checkPath(checkPath,cpath)) {
						Map<String, String> state = new HashMap<>();
						state.put("selected", "true");
						td.setState(state);
					}
				} else {
					if(checkPath(checkPath,cpath)) {
						Map<String, String> state = new HashMap<>();
						state.put("opened", "true");
						td.setState(state);
					}
				}
				td.setChildren(ctdList);
				tdList.add(td);
			}
		} catch (Exception e) {
			log.error(e.getMessage());
		}
	}
	
	private boolean checkPath(String checkPath, String cpath) {
		boolean result = false;
		if (checkPath != null && cpath != null) {
			if (!checkPath.endsWith("/")) {
				checkPath +="/";
			}
			if (!cpath.endsWith("/")) {
				cpath +="/";
			}
			if (checkPath.indexOf(cpath) != -1) {
				return true;
			}
		}
		
		return result;
	}
	
	@RequestMapping("/getData")
	public String getData(HttpServletRequest request, Model model, String path) {
		HttpSession session = request.getSession();
		String cxnstr = (String) session.getAttribute(Constants.CX_STR);
		if (StringUtils.isBlank(cxnstr)) {
			return "redirect:/";
		}
		path = StringUtils.endsWith(path, "/") ? StringUtils.substring(path, 0, StringUtils.lastIndexOf(path, "/"))
				: path;
		path = StringUtils.isBlank(path) ? "/" : StringUtils.trimToEmpty(path);
		model.addAttribute("pathList", Arrays.asList(StringUtils.split(path, "/")));

		Zk reader = new Zk(cxnstr);
		ZkData zkData = null;
		try {
			zkData = reader.readData(path);
		} catch (Exception e) {
			log.error(e.getMessage());
		}
		
		if (zkData != null) {
			model.addAttribute("data", zkData.getDataString());
			model.addAttribute("dataSize", zkData.getData() != null?zkData.getData().length:0);
			try {
				Map<String, Object> statMap = PropertyUtils.describe(zkData.getStat());
				if(statMap.containsKey("ctime")) {
					statMap.put("ctime", new Date(Long.parseLong(String.valueOf(statMap.get("ctime")))));
				}
				if(statMap.containsKey("mtime")) {
					statMap.put("mtime", new Date(Long.parseLong(String.valueOf(statMap.get("mtime")))));
				}
				statMap.remove("class");
				model.addAttribute("stat", statMap);
			} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
				log.error(e.getMessage(), e);
			}
		}

		return "right";
	}
}
